/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.src;
import java.util.List;
import java.util.ArrayList;
import org.openide.src.SourceException;
import org.openide.src.JavaDoc;
import org.openide.src.JavaDocTag;
/** Represents a JavaDoc comment block.
*
* @author Jaroslav Tulach, Petr Hrebejk, Petr Hamernik
*/
class JavaDocMemoryImpl implements JavaDoc {
protected String rawText;
private String text;
// PENDING - clear this
private static final JavaDocTagMemoryImpl[] EMPTY_ARRAY = new JavaDocTagMemoryImpl[] {};
/** Constructs the JavaDoc object held in memory. Parses the tags from rawText
*/
public JavaDocMemoryImpl( String rawText ) {
this.rawText = rawText;
}
/** Get the entire text of the comment.
* @return the whole text
*/
public String getRawText () {
return rawText;
}
/** Set the raw text of the comment.
* @param s the whole text to set
* @exception SourceException if the modification cannot be performed
*/
public void setRawText (String s) throws SourceException {
rawText = s;
}
/** Get the actual text, cleared of all (non-inline) tags.
* @return the plain text
*/
public String getText () {
if ( rawText == null )
return ""; // NOI18N
List tmp = new ArrayList();
parseComment( tmp );
return text;
}
/** Set the actual text.
* @param s the actual text, without any (non-inline) tags
* @exception SourceException if the modification cannot be performed
*/
public void setText (String s) throws SourceException {
regenerateRawText( s, getTags(), getSeeTags() );
}
/** Clears the javadoc from the source.
*/
public void clearJavaDoc() throws SourceException {
rawText = null;
}
/** Test if this javadoc is empty.
* @return true if it is not generated to the source.
*/
public boolean isEmpty() {
return rawText == null;
}
/** Gets all tags from comment.
*/
public JavaDocTag[] getTags() {
if ( rawText == null )
return EMPTY_ARRAY;
List tagList = new ArrayList();
parseComment( tagList );
JavaDocTag[] tagArray = new JavaDocTag[ tagList.size() ];
tagList.toArray( tagArray );
return tagArray;
}
/** Gets all tags of given name
*/
public JavaDocTag[] getTags( String name ) {
JavaDocTag[] allTags = getTags();
ArrayList resultList = new ArrayList( allTags.length );
for( int i = 0; i < allTags.length; i++ ) {
if ( allTags[i].name().equals( name ) )
resultList.add( allTags[i] );
}
JavaDocTag result[] = new JavaDocTag[ resultList.size() ];
resultList.toArray( result );
return result;
}
/** Adds removes or sets tags used in this comment
* @param elems the new initializers
* @param action {@link #ADD}, {@link #REMOVE}, or {@link #SET}
* @exception SourceException if impossible
*/
synchronized public void changeTags( JavaDocTag[] tags, int action ) throws SourceException {
StringBuffer sb = new StringBuffer();
switch ( action ) {
case ADD:
case SET:
sb.append( action == ADD ? getRawText() : getText() );
for( int i = 0; i < tags.length; i++ ) {
sb.append( "\n" ).append( tags[i].toString() ); // NOI18N
}
setRawText( sb.toString() );
break;
case REMOVE:
JavaDocTag currTags[] = getTags();
sb.append( getText() );
for( int i = 0; i < currTags.length; i++ ) {
boolean found = false;
String strTag = currTags[i].toString();
for( int j = 0; j < tags.length; j ++ ) {
if ( strTag.equals( tags[j].toString() ) ) {
found = true;
break;
}
}
if ( !found )
sb.append( "\n" ).append( strTag ); // NOI18N
}
setRawText( sb.toString() );
break;
}
}
/** Gets all @see tags
*/
public JavaDocTag.See[] getSeeTags() {
JavaDocTag[] allTags = getTags();
ArrayList resultList = new ArrayList( allTags.length );
for( int i = 0; i < allTags.length; i++ ) {
if ( allTags[i] instanceof JavaDocTag.See )
resultList.add( allTags[i] );
}
JavaDocTag.See result[] = new JavaDocTag.See[ resultList.size() ];
resultList.toArray( result );
return result;
}
/** Regenerates the rawText form tags
*/
protected void regenerateRawText( String text, JavaDocTag[] tags, JavaDocTag.See[] seeTags ) {
StringBuffer sb = new StringBuffer( text.length() + tags.length * 80 + seeTags.length * 80 );
sb.append( text );
for (int i = 0; i < tags.length; i++ ) {
sb.append( tags[i].toString() );
}
for (int i = 0; i < seeTags.length; i++ ) {
sb.append( seeTags[i].toString() );
}
rawText = sb.toString();
}
/** The JavaDoc of a class.
* Class javadoc adds no special tags.
*/
static class Class extends JavaDocMemoryImpl implements JavaDoc.Class {
static final long serialVersionUID =3206093459760846163L;
Class( String rawText ) {
super( rawText );
}
}
/** The JavaDoc of a field.
* <p>Currently adds special @SerialField tag
*/
static class Field extends JavaDocMemoryImpl implements JavaDoc.Field {
Field ( String rawText ) {
super( rawText );
}
/** Gets SerialField tags.
*/
public JavaDocTag.SerialField[] getSerialFieldTags() {
JavaDocTag[] allTags = this.getTags();
ArrayList resultList = new ArrayList( allTags.length );
for( int i = 0; i < allTags.length; i++ ) {
if ( allTags[i] instanceof JavaDocTag.SerialField )
resultList.add( allTags[i] );
}
JavaDocTag.SerialField result[] = new JavaDocTag.SerialField[ resultList.size() ];
resultList.toArray( result );
return result;
}
}
/** The JavaDoc of a method. Adds two special tags: @para tag and @throws tag.
*/
static class Method extends JavaDocMemoryImpl implements JavaDoc.Method {
Method ( String rawText ) {
super( rawText );
}
/** Gets param tags.
*/
public JavaDocTag.Param[] getParamTags() {
JavaDocTag[] allTags = this.getTags();
ArrayList resultList = new ArrayList( allTags.length );
for( int i = 0; i < allTags.length; i++ ) {
if ( allTags[i] instanceof JavaDocTag.Param )
resultList.add( allTags[i] );
}
JavaDocTag.Param result[] = new JavaDocTag.Param[ resultList.size() ];
resultList.toArray( result );
return result;
}
/** Gets throws tags.
*/
public JavaDocTag.Throws[] getThrowsTags() {
JavaDocTag[] allTags = this.getTags();
ArrayList resultList = new ArrayList( allTags.length );
for( int i = 0; i < allTags.length; i++ ) {
if ( allTags[i] instanceof JavaDocTag.Throws )
resultList.add( allTags[i] );
}
JavaDocTag.Throws result[] = new JavaDocTag.Throws[ resultList.size() ];
resultList.toArray( result );
return result;
}
}
// PRIVATE & UTILITY METHODS ----------------------------------------------------------
/**
* Parses the rawText and generates list of tags;
*/
private void parseComment( List tagList ) {
final int IN_TEXT = 1;
final int TAG_GAP = 2;
final int TAG_NAME = 3;
int state = TAG_GAP;
boolean newLine = true;
String tagName = null;
int tagStart = 0;
int textStart = 0;
int lastNonWhite = -1;
int len = rawText.length();
for (int inx = 0; inx < len; ++inx) {
char ch = rawText.charAt(inx);
boolean isWhite = Character.isWhitespace(ch);
switch (state) {
case TAG_NAME:
if (isWhite) {
tagName = rawText.substring(tagStart, inx);
state = TAG_GAP;
}
break;
case TAG_GAP:
if (isWhite) {
break;
}
textStart = inx;
state = IN_TEXT;
/* fall thru */
case IN_TEXT:
if (newLine && ch == '@') {
parseCommentComponent(tagList, tagName, textStart, lastNonWhite+1);
tagStart = inx;
state = TAG_NAME;
}
break;
};
if (ch == '\n') {
newLine = true;
}
else if (!isWhite) {
lastNonWhite = inx;
newLine = false;
}
}
// Finish what's currently being processed
switch (state) {
case TAG_NAME:
tagName = rawText.substring(tagStart, len);
/* fall thru */
case TAG_GAP:
textStart = len;
/* fall thru */
case IN_TEXT:
parseCommentComponent( tagList, tagName, textStart, lastNonWhite+1 );
break;
};
}
/**
* Parses the tag.
* Saves away the last parsed item.
*/
private void parseCommentComponent( List tagList, String tagName, int from, int upto) {
String tx = upto <= from ? "" : rawText.substring(from, upto); // NOI18N
if (tagName == null) {
text = tx;
}
else {
JavaDocTagMemoryImpl tag;
if (tagName.equals("@exception") || tagName.equals("@throws")) { // NOI18N
warnIfEmpty(tagName, tx);
tag = new JavaDocTagMemoryImpl.Throws(tagName, tx);
}
else if (tagName.equals("@param")) { // NOI18N
warnIfEmpty(tagName, tx);
tag = new JavaDocTagMemoryImpl.Param(tagName, tx);
}
else if (tagName.equals("@see")) { // NOI18N
warnIfEmpty( tagName, tx);
tag = new JavaDocTagMemoryImpl.See(tagName, tx);
}
else if (tagName.equals("@serialField")) { // NOI18N
warnIfEmpty( tagName, tx);
tag = new JavaDocTagMemoryImpl.SerialField(tagName, tx);
}
else if (tagName.equals("@return")) { // NOI18N
warnIfEmpty(tagName, tx);
tag = new JavaDocTagMemoryImpl(tagName, tx);
}
else if (tagName.equals("@author")) { // NOI18N
warnIfEmpty(tagName, tx);
tag = new JavaDocTagMemoryImpl(tagName, tx);
}
else if (tagName.equals("@version")) { // NOI18N
warnIfEmpty( tagName, tx);
tag = new JavaDocTagMemoryImpl(tagName, tx);
}
else {
tag = new JavaDocTagMemoryImpl(tagName, tx);
}
tagList.add(tag);
}
}
// PENDING : REMOVE THIS METHOD
private void warnIfEmpty( String tagName, String tx) {
/*
if (tx.length() == 0) {
System.out.println("tag.tag_has_no_arguments" + tagName);
}
*/
}
}
/*
* Log
* 9 Gandalf 1.8 1/16/00 Ian Formanek Removed semicolons after
* methods body to prevent fastjavac from complaining
* 8 Gandalf 1.7 1/12/00 Petr Hamernik i18n using perl script
* (//NOI18N comments added)
* 7 Gandalf 1.6 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 6 Gandalf 1.5 8/17/99 Petr Hrebejk changeTags meyhod
* implemented
* 5 Gandalf 1.4 8/9/99 Ian Formanek Generated Serial Version
* UID
* 4 Gandalf 1.3 7/26/99 Petr Hrebejk getParamTags,
* getThrowsTag, .... methods implemented
* 3 Gandalf 1.2 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 2 Gandalf 1.1 6/7/99 Petr Hrebejk Implementations made
* package privet
* 1 Gandalf 1.0 5/26/99 Petr Hrebejk
* $
*/